#ifndef BOUNDING_BOX_HPP
#define BOUNDING_BOX_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include "BoundingVolume.hpp"

#include <SmegTools/Config.h>
#include <SmegTools/Debug/DebugNew.hpp>

namespace smeg {
    namespace math {
////////////////////////////////////////////////////////////
/// Axis Aligned Bounding Box Volume
////////////////////////////////////////////////////////////
class BoundingBox : public BoundingVolume
{
public:
    enum eCorner {
        eTopLeft        = 0,
        eTopRight       = 1,
        eBottomRight    = 2,
        eBottomLeft     = 3
    };
    enum eAxis {
        eXAxis          = 0,
        eYAxis          = 1
    };

    ////////////////////////////////////////////////////////////
    /// Default Constructor
    ///
    /// \param _Center : Center of the BoundingBox
    /// \param _Size :  Size of the BoundingBox
    ///
    ////////////////////////////////////////////////////////////
                        BoundingBox( const sf::Vector2f& _Center = sf::Vector2f(), 
                                        const sf::Vector2f& _Size = sf::Vector2f(),
                                        float _fRotation = 0.0f );
    ////////////////////////////////////////////////////////////
    /// Copy Constructor
    ///
    /// \param _Copy
    ///
    ////////////////////////////////////////////////////////////
                        BoundingBox( const BoundingBox& _Copy );
    ////////////////////////////////////////////////////////////
    /// Destructor
    ///
    ////////////////////////////////////////////////////////////
    virtual             ~BoundingBox();

    DECLARE_CLONE_FUNC( BoundingBox, BoundingVolume )
    
    ////////////////////////////////////////////////////////////
    /// Setup the Bounding Volume
    ///
    /// \param _Center : Center of the Bounding Volume
    /// \param _Size :  Size of the Bounding Volume
    ///
    ////////////////////////////////////////////////////////////
    virtual void        Setup( const sf::Vector2f& _Center, const sf::Vector2f& _Size, float _fRotation = 0.0f );
    
    ////////////////////////////////////////////////////////////
    /// Does the Bounding Volume overlaps with a Bounding Volume
    ///
    /// \param _Other : Other Volume to test
    ///
    /// \return Whether the _Other Bounding Volume overlaps with this Bounding Volume
    ///
    ////////////////////////////////////////////////////////////
    virtual bool        Overlaps( const BoundingBox& _Other ) const;
    virtual bool        Overlaps( const Line& _Other ) const;
    virtual bool        Overlaps( const Circle& _Other ) const;
    
    ////////////////////////////////////////////////////////////
    /// Does the Bounding Volume contains a Bounding Volume
    ///
    /// \param _Other : Other Volume to test
    ///
    /// \return Whether this contains the _Other Bounding Volume
    ///
    ////////////////////////////////////////////////////////////
    virtual bool        Contains( const BoundingBox& _Other ) const;
    virtual bool        Contains( const Line& _Other ) const;
    virtual bool        Contains( const Circle& _Other ) const;

    ////////////////////////////////////////////////////////////
    /// Does the Bounding Volume contains a point
    ///
    /// \param _Point : Point to test
    ///
    /// \return Whether this contains the point
    ///
    ////////////////////////////////////////////////////////////
    virtual bool        Contains( const sf::Vector2f& _Point ) const;

    ////////////////////////////////////////////////////////////
    /// Helper function for the Cohen-Sutherland algorithm
    /// http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
    /// This function will compute where the point ( _fX, _fY ) is
    /// compared to the BoundingBox (top, left, top-right, etc...)
    ///
    ////////////////////////////////////////////////////////////
    int                 ComputeOutCode( float _fX, float _fY ) const;

    /*********************** Accessors ************************/
    virtual void        SetCenter( float _fX, float _fY );
    virtual void        MoveCenter( float _fX, float _fY );

    bool                IsAxisAligned() const;
    void                SetRotation( float _fRotation );
    
    const sf::Vector2f* GetCorners() const;
    const sf::Vector2f& GetLowerBound() const;
    const sf::Vector2f& GetUpperBound() const;
    const sf::Vector2f* GetAxis() const;

    Line                GetLeftLine() const;
    Line                GetRightLine() const;
    Line                GetTopLine() const;
    Line                GetBottomLine() const;

    virtual float       GetPseudoRadius() const;

protected:
    ////////////////////////////////////////////////////////////
    /// Compute the box
    ///
    ////////////////////////////////////////////////////////////
    void                ComputeBox();

    /******************* Protected members ********************/
    bool                m_bIsAxisAligned;
    sf::Vector2f        m_Corners[4];

    float               m_fRotation;
    sf::Vector2f        m_Axis[2];

#ifdef _DEBUG
public:
    virtual void        DebugRender( sf::RenderWindow* _pRenderWindow, const sf::Color& _Color = sf::Color::White, bool _bFull = false ) const;
#endif // _DEBUG
};

/************************** Inline ************************/
inline bool BoundingBox::IsAxisAligned() const {
    return m_bIsAxisAligned;
}

inline const sf::Vector2f* BoundingBox::GetCorners() const {
    return m_Corners;
}

inline const sf::Vector2f& BoundingBox::GetLowerBound() const {
    return m_Corners[eTopLeft];
}

inline const sf::Vector2f& BoundingBox::GetUpperBound() const {
    return m_Corners[eBottomRight];
}

inline const sf::Vector2f* BoundingBox::GetAxis() const {
    return m_Axis;
}


    } // namespace math
} // namespace smeg

#include <SmegTools/Debug/DebugNewOff.hpp>

#endif // BOUNDING_BOX_HPP
